/*
 * LCD厂家没有引出SDO管脚，无法验证写入的寄存器是否正确，前期一直误以为SDI和SDO复用
 * 
 * 2020-8-29 fix lcd花屏判断并重启
 *  store_dump抓取部分寄存器做调试依据、have_been_init根据调试依据执行重启
 *      
 * 
*/
/*
PINID_SSP3_SCK MXS_PIN_ENCODE(2,24)
PINID_SSP3_MOSI MXS_PIN_ENCODE(2,25)
PINID_SSP3_MISO MXS_PIN_ENCODE(2,26)
PINID_SSP3_SS0 MXS_PIN_ENCODE(2,27)

echo 88 > /sys/class/gpio/export
echo 89 > /sys/class/gpio/export
echo 90 > /sys/class/gpio/export
echo 91 > /sys/class/gpio/export


echo out > /sys/class/gpio/gpio88/direction
echo out > /sys/class/gpio/gpio89/direction
echo out > /sys/class/gpio/gpio90/direction
echo out > /sys/class/gpio/gpio91/direction

echo 0 > /sys/class/gpio/gpio88/value
echo 0 > /sys/class/gpio/gpio89/value
echo 0 > /sys/class/gpio/gpio90/value
echo 0 > /sys/class/gpio/gpio91/value


echo 1 > /sys/class/gpio/gpio88/value
echo 1 > /sys/class/gpio/gpio89/value
echo 1 > /sys/class/gpio/gpio90/value
echo 1 > /sys/class/gpio/gpio91/value


echo 1 > /sys/class/misc/abcd/lcd_spi 
*/

#include <linux/slab.h>
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/fsl_devices.h>
#include <linux/delay.h>
#include <linux/irq.h>

#include <mach/hardware.h>
#include <mach/lradc.h>
#include <mach/device.h>
#include <mach/regs-lradc.h>
#include <../arch/arm/mach-mx28/mx28_pins.h>
#include <mach/pinctrl.h>
#include <linux/timer.h>
#include <linux/syscalls.h>
#include <linux/backlight-misc.h>



#include <linux/init.h>
#include <linux/module.h>
// #include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/kernel.h>
#include "linux/platform_device.h"
#include "mach/pinctrl.h"
#include <linux/delay.h>
int SPI_CLK, SPI_RES, SPI_DI, SPI_CS, SPI_DO;

#define USE_DO (0)

static struct miscdevice *pmisc;

struct misc_lcd_spi_data {
	char name[16];
    struct timer_list timer;
    int finish;
    int ack;
    struct completion s_finish;
    struct completion s_ack;
};

void do_transfer();
void LCD_Init(void);
static ssize_t have_been_init();
#define BAD_TIMING (0)
void SPI_WriteComm(unsigned int i)
{ 
    unsigned char n,m;
    
    gpio_set_value(SPI_CS, 0);
    udelay(10);
    gpio_set_value(SPI_CLK, 0);
    udelay(10);
    gpio_set_value(SPI_DI, 0);
    udelay(10);
    gpio_set_value(SPI_CLK, 1);

    m=0x80;
    for (n = 0; n < 8; n++)
    {
        gpio_set_value(SPI_CLK, 0);
        udelay(10);
        if (i & m)
        {
            gpio_set_value(SPI_DI, 1);
        }
        else
        {
            gpio_set_value(SPI_DI, 0);
        }
        m = m >> 1;
        gpio_set_value(SPI_CLK, 1);
        udelay(10);
    }
#if BAD_TIMING
     gpio_set_value(SPI_CS, 1);
#endif
} 

// void SPI_WriteData(unsigned int i)
// { 
//     unsigned char n,m;
// #if BAD_TIMING
//     gpio_set_value(SPI_CS, 0);
// #endif
//     gpio_set_value(SPI_CLK, 0);
//     udelay(10);
//     gpio_set_value(SPI_DI, 1);
//     udelay(10);
//     gpio_set_value(SPI_CLK, 1);
     
//     m=0x80;
//     for (n = 0; n < 8; n++)
//     {
//         gpio_set_value(SPI_CLK, 0);
//         udelay(10);
//         if (i & m)
//         {
//             gpio_set_value(SPI_DI, 1);
//         }
//         else
//         {
//             gpio_set_value(SPI_DI, 0);
//         }
//         gpio_set_value(SPI_CLK, 1);
//         udelay(10);
//         m = m >> 1;
//     }
//      gpio_set_value(SPI_CS, 1);
// } 


void SPI_WriteData(unsigned int i)
{ 
    unsigned char n,m, d;
    int bit;
#if BAD_TIMING
    gpio_set_value(SPI_CS, 0);
#endif
    gpio_set_value(SPI_CLK, 0);
    udelay(10);
    gpio_set_value(SPI_DI, 1);
    udelay(10);
#if USE_DO
    bit = gpio_get_value(SPI_DO);
    // printk("[%x] ", bit);
    d = d << 1;
    if (bit) {
        d |= 0x01;
    }
#endif
    gpio_set_value(SPI_CLK, 1);
     
    m=0x80;
    for (n = 0; n < 8; n++)
    {
        gpio_set_value(SPI_CLK, 0);
        udelay(10);
        if (i & m)
        {
            gpio_set_value(SPI_DI, 1);
        }
        else
        {
            gpio_set_value(SPI_DI, 0);
        }
#if USE_DO
        if (n != 7) {
            bit = gpio_get_value(SPI_DO);
            d = d << 1;
            if (bit) {
                d |= 0x01;
            }
        }
#endif
        gpio_set_value(SPI_CLK, 1);
        udelay(10);
        m = m >> 1;
    }
     gpio_set_value(SPI_CS, 1);
    //  printk("[%x]\r\n", d);
} 

void SPI_ReadData(unsigned int *data)
{
    unsigned char n,m;
    int bit;
    m=0x80;
    gpio_set_value(SPI_DI, 1);
    
    gpio_direction_input(SPI_DI);
    
    for(n=0; n<8; n++)
    {
        gpio_set_value(SPI_CLK, 0);
        udelay(1000);
        
        gpio_set_value(SPI_CLK, 1);
        udelay(1000);
        // TODO LCD封装有缺陷，没有引出SDO管脚，无法实现读取
        bit = gpio_get_value(SPI_DI);
        // bit = gpio_get_value(SPI_DO);
        // printk("[%x] ", bit);
        
        
        
        m = m << 1;
        if (bit) {
            m |= 0x01;
        }
        
    }
    *data = m;
    gpio_direction_output(SPI_DI, 0);
    gpio_set_value(SPI_CLK, 0);  //  最后需要一个空时钟，筹够9个bit？
    gpio_set_value(SPI_CLK, 1);
    gpio_set_value(SPI_CS, 1);
} 

void SPI_Finish()
{
    gpio_set_value(SPI_CS, 1);
}

static ssize_t spi_reset_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    char *after;

    gpio_set_value(SPI_RES, buf[0] == '1' ? 1 : 0);
	return count;
}


static ssize_t spi_cs_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    char *after;
    gpio_set_value(SPI_CS, buf[0] == '1' ? 1 : 0);
	return count;
}


static ssize_t spi_clk_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    char *after;
    
    gpio_set_value(SPI_CLK, buf[0] == '1' ? 1 : 0);
	return count;
}


static ssize_t spi_di_store(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    char *after;
    
    gpio_set_value(SPI_DI, buf[0] == '1' ? 1 : 0);
	return count;
}


static ssize_t init(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    printk("do init lcd spi!!!\r\n");
    LCD_Init();
    if (-1 == have_been_init()) {  /* 再次读取芯片状态，是否挂了，上面的复位是否成功 */
        printk("times 1 reset nv3052c\r\n");
        LCD_Init();                /* 最后绝招，控制芯片RESET，重新初始化，必定成功，再不成功不理它*/
    }
	return count;
}

static ssize_t retry(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
    printk("retry init lcd spi!!!\r\n");
    do_transfer();
	return count;
}

void DispRegValue(unsigned int RegIndex,unsigned char ParNum)
{
    unsigned int reg_data[20], data, i;	
    SPI_WriteComm(RegIndex);
    if(ParNum>20)
		ParNum=20;
    for(i=0;i<ParNum;i++)
	{
		// reg_data[i]=();
        SPI_ReadData(&data);
        printk("read reg 0x%.2x out 0x%.2x\r\n", RegIndex, data);
	}
}
static ssize_t store_dump(
    struct device *dev,
    struct device_attribute *attr,
    const char *buf,
    size_t count)
{
#if 1
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x00);  /* Page 0 */
  
    // SPI_WriteComm(0xff);SPI_WriteData(0x01);  // 这两行有没有没问题
    // SPI_WriteComm(0x48);SPI_WriteData(0x0e);  // 这两行有没有没问题
    
    // SPI_WriteComm(0x20);
    // msleep(1000);
    SPI_WriteComm(0x21);
    SPI_WriteComm(0x20);

    
    // SPI_WriteComm(0x35);SPI_WriteData(0x0);
    // SPI_WriteComm(0x3a);SPI_WriteData(0x50);
    // SPI_WriteComm(0x0a);SPI_WriteData(0x48);
    // SPI_WriteComm(0x0c);SPI_WriteData(0x50);
    // DispRegValue(0x3a, 1);
/*
正常时候
---------------------------------------
<4>[  770.770000] read reg 0x0a out 0x9c
<4>[  770.800000] read reg 0x0c out 0x70
<4>[  770.820000] read reg 0x0d out 0x00
<4>[  770.840000] read reg 0x0e out 0x00
<4>[  770.860000] read reg 0x0f out 0xc0  这个不稳定
<4>[  770.890000] read reg 0x36 out 0xff
<4>[  770.910000] read reg 0x3a out 0xff
<4>[  770.930000] read reg 0x45 out 0x00
<4>[  770.960000] read reg 0x47 out 0x00
<4>[  771.000000] read reg 0x52 out 0xc0  这个不稳定
<4>[  771.040000] read reg 0x54 out 0x2c
<4>[  771.070000] read reg 0x56 out 0x01
<4>[  771.090000] read reg 0x5f out 0x00
<4>[  771.110000] read reg 0xda out 0x40  手册是0x30
<4>[  771.130000] read reg 0xdb out 0x00  手册是0x52
<4>[  771.160000] read reg 0xdc out 0xff  手册是0x01
<4>[  771.160000] read reg 0xf8 out 0xff

出问题时候（x轴镜像）这个时候只需要 do_transfer()就能显示正常，
但是要寄存器全部正常，还是得LCD_Init
-----------------
<4>[ 1159.720000] read reg 0x0a out 0x9c
<4>[ 1159.740000] read reg 0x0c out 0x70
<4>[ 1159.760000] read reg 0x0d out 0x00
<4>[ 1159.780000] read reg 0x0e out 0x00
<4>[ 1159.800000] read reg 0x0f out 0x00
<4>[ 1159.830000] read reg 0x36 out 0xff
<4>[ 1159.850000] read reg 0x3a out 0xff
<4>[ 1159.870000] read reg 0x45 out 0x00
<4>[ 1159.890000] read reg 0x47 out 0x00
<4>[ 1159.920000] read reg 0x52 out 0x00
<4>[ 1159.940000] read reg 0x54 out 0x00
<4>[ 1159.960000] read reg 0x56 out 0x00
<4>[ 1159.980000] read reg 0x5f out 0x00
<4>[ 1160.000000] read reg 0xda out 0x30  手册是0x30
<4>[ 1160.030000] read reg 0xdb out 0x52  手册是0x52
<4>[ 1160.050000] read reg 0xdc out 0xff  手册是0x01
<4>[ 1160.070000] read reg 0xf8 out 0xff
*/
    DispRegValue(0x0a, 1);                    // 关键看这个Display Power Mode
    DispRegValue(0x0c, 1);
    DispRegValue(0x0d, 1);
    DispRegValue(0x0e, 1);
    DispRegValue(0x0f, 1);
    DispRegValue(0x36, 1);
    DispRegValue(0x3a, 1);
    
    DispRegValue(0x45, 1);
    DispRegValue(0x47, 1);

    DispRegValue(0x52, 1);
    DispRegValue(0x54, 1);
    DispRegValue(0x56, 1);
    DispRegValue(0x5f, 1);
    DispRegValue(0xda, 1);
    DispRegValue(0xdb, 1);
    DispRegValue(0xdc, 1);
    DispRegValue(0xf8, 1);
    // DispRegValue(0x22, 1);
    // DispRegValue(0x23, 1);
    return count;
#else // 不能乱读    
    // 测试32个寄存器，下面两个不能操作
    // Reg 0x01  soft reset LCD熄灭，除非重新初始化
    // Reg 0x10 sleep in  LCD熄灭，发送【读取】Reg 0x11 Sleep out可恢复
    int i;
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x00);  /* Page 0 */
    printk("page 0\r\n");
    for (i = 0;i < 256; i++) {
        if (i == 0x10 || i == 0x01) {
            continue;
        }
        DispRegValue(i, 1);
    }

    printk("page 1\r\n");
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x01);  /* Page 0 */
    for (i = 0;i < 256; i++) {
        DispRegValue(i, 1);
    }

    printk("page 2\r\n");
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x02);  /* Page 0 */
    for (i = 0;i < 256; i++) {
        DispRegValue(i, 1);
    }
    printk("page 3\r\n");
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x03);  /* Page 0 */
    for (i = 0;i < 256; i++) {
        DispRegValue(i, 1);
    }
#endif
}




/*
 * 某些时候lcd初始化失败：排线过长、初始化时序被干扰，lcd会花屏。
 * 如果带点插入LCD排线，此时读取LCD寄存器，必定是非 0x9c 
 * 
 * 
 * --------------如果以后还有问题，就多读取几个寄存器做判断---------
 * 
 * 
*/
static ssize_t have_been_init()
{
    unsigned int data0a_1, data0a_2, data0a_3;
    unsigned int data54, data56;
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x00);  /* Page 0 */
  
    SPI_WriteComm(0x0a);SPI_ReadData(&data0a_1);  // 关键看这个 Read Display Power Mode
    SPI_WriteComm(0x0a);SPI_ReadData(&data0a_2);  // 防范编程
    SPI_WriteComm(0x0a);SPI_ReadData(&data0a_3);

    SPI_WriteComm(0x54);SPI_ReadData(&data54);
    SPI_WriteComm(0x56);SPI_ReadData(&data56);
    
    /*
    sleep out:1
    normal: 1
    disp_on: 1

    偶尔发现，读取数据是0xff，lcd显示也是正常（刚刚插入LCD排线时）
    */
    if (data0a_1 == 0x9c && data0a_2 == 0x9c && data0a_3 == 0x9c &&
        data54 == 0x2c && data56 == 0x01) {
        return 0;
    }
    else {  /* 大多数时候返回的是 0xdc */
        printk("data %x %x %x\r\n", data0a_1, data0a_2, data0a_3);
        return -1;
    }
}

static DEVICE_ATTR(
    init, S_IWUSR | S_IRUGO, NULL, init);
static DEVICE_ATTR(
    retry, S_IWUSR | S_IRUGO, NULL, retry);
static DEVICE_ATTR(
    dump, S_IWUSR | S_IRUGO, NULL, store_dump);
static DEVICE_ATTR(
    RESET, S_IWUSR | S_IRUGO, NULL, spi_reset_store);
static DEVICE_ATTR(
    CS, S_IWUSR | S_IRUGO, NULL, spi_cs_store);
static DEVICE_ATTR(
    DI, S_IWUSR | S_IRUGO, NULL, spi_di_store);
static DEVICE_ATTR(
    CLK, S_IWUSR | S_IRUGO, NULL, spi_clk_store);

struct misc_lcd_spi_data *pdata;

/*
 * 偶尔初始化不成功，有两个处理方法：
 * 方法1：用这个定时任务每5秒执行一次初始化，当然，不会控制RESET管脚完全复位，
 * 若下拉RESET将导致屏幕完全黑掉，它影响正常使用。
 * 方法2：读取所有寄存器，比价和写入的是否一致，首先要gpio_direction_input，修改方向，
 * 但是mxs287的gpio_get_value总是返回32bit数据，读取SDI总是返回，
 * 0x200000(第27bit是高)，所以这个方法没有使用
 */
static void fix_transfer_fail(unsigned long _data)
{
    struct misc_lcd_spi_data *pdata = (struct misc_lcd_spi_data *)_data;
    // 执行rmmod 后lcd_spi_exit被调用，发送完成信号
    if (try_wait_for_completion(&pdata->s_finish)) {
        // 通知lcd_spi_exit可以退出了
        complete(&pdata->s_ack);
        return ;
    }
    
    if (-1 == have_been_init()) {  /* 定时读取芯片状态，是否挂了 */
        printk("times 1 reset nv3052c\r\n");
        do_transfer();             /* 不控制RESET，直接发送初始化，为了避免LCD向上滚动 */
    }
    mdelay(100);
    if (-1 == have_been_init()) {  /* 再次读取芯片状态，是否挂了，上面的复位是否成功 */
        printk("times 2 reset nv3052c\r\n");
        LCD_Init();                /* 最后绝招，控制芯片RESET，重新初始化，必定成功，再不成功不理它*/
    }
    if (-1 == have_been_init()) {  /* 一般情况不会运行到这里 */
        printk("times 3 reset nv3052c\r\n");
        LCD_Init();
    }
    /* 想快速看到白屏、花屏，就把这个10秒改成3秒，只有在插入排线并发送配置数据才容易出问题 */
    mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(15000));
}
int __init lcd_spi_init(void)
{
    #if 0
    SPI_RES = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,26));
    SPI_CS   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,27));
    SPI_CLK  = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,24));
    SPI_DI   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,25));
    #else 
    SPI_RES = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,20)); SPI_CLK  = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,26));
    SPI_DI   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,21)); SPI_CS   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,27));
#if USE_DO
    SPI_DO   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,12));
#endif    
    //                                                 SPI_CS   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,12));
    // SPI_RES = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(2,14));
    // SPI_CLK  = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,6));SPI_DI   = MXS_PIN_TO_GPIO(MXS_PIN_ENCODE(3,9));  
    
    
    #endif

    int ret;
    gpio_free(SPI_RES);
    ret = gpio_request(SPI_RES, "reset spi");
    if (ret) {
        printk("fail request spi ");
    }
    gpio_free(SPI_CLK);
    ret = gpio_request(SPI_CLK, "reset clk");
    if (ret) {
        printk("fail request clk ");
    }
    gpio_free(SPI_DI);
    ret = gpio_request(SPI_DI, "reset di");
    if (ret) {
        printk("fail request di ");
    }
    gpio_free(SPI_CS);
    ret = gpio_request(SPI_CS, "reset cs");
    if (ret) {
        printk("fail request cs");
    }
#if USE_DO
    gpio_free(SPI_DO);
    ret = gpio_request(SPI_DO, "SDO");
    if (ret) {
        printk("fail request DO");
    }
#endif
    gpio_direction_output(SPI_RES, 1);
    gpio_direction_output(SPI_CLK, 1);
    gpio_direction_output(SPI_DI, 1);
    gpio_direction_output(SPI_CS, 1);
#if USE_DO
    gpio_direction_input(SPI_DO);
#endif

    struct device         *this_dev;
    


    
    
    pmisc = kzalloc(sizeof(struct miscdevice), GFP_KERNEL);
    pdata = kzalloc(sizeof(struct misc_lcd_spi_data), GFP_KERNEL);
    
    

    pmisc->name  = "lcd-nv3052c";
    pmisc->minor = MISC_DYNAMIC_MINOR;
    pmisc->fops  = NULL;
    misc_register(pmisc);
    
    this_dev                = pmisc->this_device;
    this_dev->platform_data = pdata;
    device_create_file(this_dev, &dev_attr_init);
    device_create_file(this_dev, &dev_attr_retry);
    device_create_file(this_dev, &dev_attr_RESET);
    device_create_file(this_dev, &dev_attr_CS);
    device_create_file(this_dev, &dev_attr_DI);
    device_create_file(this_dev, &dev_attr_CLK);
    device_create_file(this_dev, &dev_attr_dump);


    pdata->finish = 0;
    pdata->ack = 0;
    init_completion(&pdata->s_finish);
    init_completion(&pdata->s_ack);
    setup_timer(&pdata->timer, fix_transfer_fail, pdata);
    mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(1000));

    /* echo 1 > /sys/class/backlight/mxs-bl/bl_power */
    if (-1 == have_been_init()) {  /* uboot 没有对lcd初始化 */    
        LCD_Init();  /* 初始化难免引起LCD向上滚动，解决方法是关闭LCD背光 */
    }
    if (-1 == have_been_init()) {  /* 是否一次初始化就成功了，否则再来一次 */
        printk("times 2 reset nv3052c\r\n");
        LCD_Init();
    }
    /* echo 0 > /sys/class/backlight/mxs-bl/bl_power */
    return 0;
}


void __exit lcd_spi_exit(void)
{
#if 1
    complete(&pdata->s_finish);
    mod_timer(&pdata->timer, jiffies + msecs_to_jiffies(10));  // 强制将数秒被调度的timer，修改成10ms调度，通知该结束了
    if(wait_for_completion_timeout(&pdata->s_ack, msecs_to_jiffies(7000))) {  // 应该不会发生这样的BUG：7秒timer不被调度
        printk("wait timer off\r\n");
    }
    printk("All timer exit---\r\n");
#endif
    if (pmisc) {
        misc_deregister(pmisc);
    }

    gpio_free(SPI_RES);
}



void LCD_Init(void)
{

 	unsigned char i;

    gpio_set_value(SPI_CS, 0);
	gpio_set_value(SPI_RES, 1);
	mdelay(200);
    printk("reset pin down\r\n");
	gpio_set_value(SPI_RES, 0);
    mdelay(200);
    // mdelay(2000);
    printk("reset pin up\r\n");
    gpio_set_value(SPI_RES, 1);
	mdelay(200);

    do_transfer();   

    SPI_WriteComm(0x11);SPI_WriteData(0x00);	 //sleep out
    mdelay(200);
    SPI_WriteComm(0x29);SPI_WriteData(0x00);	  //display on
    mdelay(10); 
    gpio_set_value(SPI_CS, 1);
}

void dump_data(int addr, int count)
{
    int data;
    if (count >= 3) {
        count = 3;
    }
    SPI_WriteComm(addr);
    SPI_ReadData(&data);
    SPI_Finish();
    printk("%.2x: ", addr);
    while(count--) {
        printk("%.2x ", data);
    }
    printk("\r\n");
}
// 这里是初始化
void do_transfer()
{
    // printk("%s(): %d\r\n", __FUNCTION__, __LINE__);
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);  /* 翻页要写3次 */
    SPI_WriteComm(0xFF);SPI_WriteData(0x01);  /* 翻页要写3次 */
    SPI_WriteComm(0xE3);SPI_WriteData(0x00); //DispRegValue(0xE3, 1);
    SPI_WriteComm(0x40);SPI_WriteData(0x00); //DispRegValue(0x40, 1);
    SPI_WriteComm(0x03);SPI_WriteData(0x40); //DispRegValue(0x03, 1);
    SPI_WriteComm(0x04);SPI_WriteData(0x00);
    SPI_WriteComm(0x05);SPI_WriteData(0x03);
    SPI_WriteComm(0x08);SPI_WriteData(0x00);
    SPI_WriteComm(0x09);SPI_WriteData(0x07);
    SPI_WriteComm(0x0A);SPI_WriteData(0x01);//DispRegValue(0x0a, 1); /* 写入后立即读取，一次读取1byte */
    SPI_WriteComm(0x0B);SPI_WriteData(0x32);//DispRegValue(0x0B, 1);
    SPI_WriteComm(0x0C);SPI_WriteData(0x32); // raw
    SPI_WriteComm(0x0D);SPI_WriteData(0x0B);
    SPI_WriteComm(0x0E);SPI_WriteData(0x00);
    SPI_WriteComm(0x23);SPI_WriteData(0xA2);

    SPI_WriteComm(0x24);SPI_WriteData(0x0c);
    SPI_WriteComm(0x25);SPI_WriteData(0x06);
    SPI_WriteComm(0x26);SPI_WriteData(0x14);
    SPI_WriteComm(0x27);SPI_WriteData(0x14);

    SPI_WriteComm(0x38);SPI_WriteData(0x9C); 
    SPI_WriteComm(0x39);SPI_WriteData(0xA7); 
    SPI_WriteComm(0x3A);SPI_WriteData(0x3a); 

    SPI_WriteComm(0x28);SPI_WriteData(0x40);
    SPI_WriteComm(0x29);SPI_WriteData(0x01);
    SPI_WriteComm(0x2A);SPI_WriteData(0xdf);
    SPI_WriteComm(0x49);SPI_WriteData(0x3C);   
    SPI_WriteComm(0x91);SPI_WriteData(0x57); 
    SPI_WriteComm(0x92);SPI_WriteData(0x57); 
    SPI_WriteComm(0xA0);SPI_WriteData(0x55);
    SPI_WriteComm(0xA1);SPI_WriteData(0x50);
    SPI_WriteComm(0xA4);SPI_WriteData(0x9C);
    SPI_WriteComm(0xA7);SPI_WriteData(0x02);  
    SPI_WriteComm(0xA8);SPI_WriteData(0x01);  
    SPI_WriteComm(0xA9);SPI_WriteData(0x01);  
    SPI_WriteComm(0xAA);SPI_WriteData(0xFC);  
    SPI_WriteComm(0xAB);SPI_WriteData(0x28);  
    SPI_WriteComm(0xAC);SPI_WriteData(0x06);  
    SPI_WriteComm(0xAD);SPI_WriteData(0x06);  
    SPI_WriteComm(0xAE);SPI_WriteData(0x06);  
    SPI_WriteComm(0xAF);SPI_WriteData(0x03);  
    SPI_WriteComm(0xB0);SPI_WriteData(0x08);  
    SPI_WriteComm(0xB1);SPI_WriteData(0x26);  
    SPI_WriteComm(0xB2);SPI_WriteData(0x28);  
    SPI_WriteComm(0xB3);SPI_WriteData(0x28);  
    SPI_WriteComm(0xB4);SPI_WriteData(0x33);  
    SPI_WriteComm(0xB5);SPI_WriteData(0x08);  
    SPI_WriteComm(0xB6);SPI_WriteData(0x26);  
    SPI_WriteComm(0xB7);SPI_WriteData(0x08);  
    SPI_WriteComm(0xB8);SPI_WriteData(0x26); 
    SPI_WriteComm(0xF0);SPI_WriteData(0x00); 
    SPI_WriteComm(0xF6);SPI_WriteData(0xC0);


    SPI_WriteComm(0xFF);SPI_WriteData(0x30);
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);
    SPI_WriteComm(0xFF);SPI_WriteData(0x02);
    SPI_WriteComm(0xB0);SPI_WriteData(0x0B);
    SPI_WriteComm(0xB1);SPI_WriteData(0x16);
    SPI_WriteComm(0xB2);SPI_WriteData(0x17); 
    SPI_WriteComm(0xB3);SPI_WriteData(0x2C); 
    SPI_WriteComm(0xB4);SPI_WriteData(0x32);  
    SPI_WriteComm(0xB5);SPI_WriteData(0x3B);  
    SPI_WriteComm(0xB6);SPI_WriteData(0x29); 
    SPI_WriteComm(0xB7);SPI_WriteData(0x40);   
    SPI_WriteComm(0xB8);SPI_WriteData(0x0d);
    SPI_WriteComm(0xB9);SPI_WriteData(0x05);
    SPI_WriteComm(0xBA);SPI_WriteData(0x12);
    SPI_WriteComm(0xBB);SPI_WriteData(0x10);
    SPI_WriteComm(0xBC);SPI_WriteData(0x12);
    SPI_WriteComm(0xBD);SPI_WriteData(0x15);
    SPI_WriteComm(0xBE);SPI_WriteData(0x19);              
    SPI_WriteComm(0xBF);SPI_WriteData(0x0E);
    SPI_WriteComm(0xC0);SPI_WriteData(0x16);  
    SPI_WriteComm(0xC1);SPI_WriteData(0x0A);
    SPI_WriteComm(0xD0);SPI_WriteData(0x0C);
    SPI_WriteComm(0xD1);SPI_WriteData(0x17);
    SPI_WriteComm(0xD2);SPI_WriteData(0x14);
    SPI_WriteComm(0xD3);SPI_WriteData(0x2E);   
    SPI_WriteComm(0xD4);SPI_WriteData(0x32);   
    SPI_WriteComm(0xD5);SPI_WriteData(0x3C);  
    SPI_WriteComm(0xD6);SPI_WriteData(0x22);
    SPI_WriteComm(0xD7);SPI_WriteData(0x3D);
    SPI_WriteComm(0xD8);SPI_WriteData(0x0D);
    SPI_WriteComm(0xD9);SPI_WriteData(0x07);
    SPI_WriteComm(0xDA);SPI_WriteData(0x13);
    SPI_WriteComm(0xDB);SPI_WriteData(0x13);
    SPI_WriteComm(0xDC);SPI_WriteData(0x11);
    SPI_WriteComm(0xDD);SPI_WriteData(0x15);
    SPI_WriteComm(0xDE);SPI_WriteData(0x19);                   
    SPI_WriteComm(0xDF);SPI_WriteData(0x10);
    SPI_WriteComm(0xE0);SPI_WriteData(0x17);    
    SPI_WriteComm(0xE1);SPI_WriteData(0x0A);
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);
    SPI_WriteComm(0xFF);SPI_WriteData(0x03);   
    SPI_WriteComm(0x00);SPI_WriteData(0x2A);
    SPI_WriteComm(0x01);SPI_WriteData(0x2A);
    SPI_WriteComm(0x02);SPI_WriteData(0x2A);
    SPI_WriteComm(0x03);SPI_WriteData(0x2A);
    SPI_WriteComm(0x04);SPI_WriteData(0x61);  
    SPI_WriteComm(0x05);SPI_WriteData(0x80);   
    SPI_WriteComm(0x06);SPI_WriteData(0xc7);   
    SPI_WriteComm(0x07);SPI_WriteData(0x01);  
    SPI_WriteComm(0x08);SPI_WriteData(0x03); 
    SPI_WriteComm(0x09);SPI_WriteData(0x04);
    SPI_WriteComm(0x70);SPI_WriteData(0x22);
    SPI_WriteComm(0x71);SPI_WriteData(0x80);
    SPI_WriteComm(0x30);SPI_WriteData(0x2A);
    SPI_WriteComm(0x31);SPI_WriteData(0x2A);
    SPI_WriteComm(0x32);SPI_WriteData(0x2A);
    SPI_WriteComm(0x33);SPI_WriteData(0x2A);
    SPI_WriteComm(0x34);SPI_WriteData(0x61);
    SPI_WriteComm(0x35);SPI_WriteData(0xc5);
    SPI_WriteComm(0x36);SPI_WriteData(0x80);
    SPI_WriteComm(0x37);SPI_WriteData(0x23);
    SPI_WriteComm(0x40);SPI_WriteData(0x03); 
    SPI_WriteComm(0x41);SPI_WriteData(0x04); 
    SPI_WriteComm(0x42);SPI_WriteData(0x05); 
    SPI_WriteComm(0x43);SPI_WriteData(0x06); 
    SPI_WriteComm(0x44);SPI_WriteData(0x11); 
    SPI_WriteComm(0x45);SPI_WriteData(0xe8); 
    SPI_WriteComm(0x46);SPI_WriteData(0xe9); 
    SPI_WriteComm(0x47);SPI_WriteData(0x11);
    SPI_WriteComm(0x48);SPI_WriteData(0xea); 
    SPI_WriteComm(0x49);SPI_WriteData(0xeb);
    SPI_WriteComm(0x50);SPI_WriteData(0x07); 
    SPI_WriteComm(0x51);SPI_WriteData(0x08); 
    SPI_WriteComm(0x52);SPI_WriteData(0x09); 
    SPI_WriteComm(0x53);SPI_WriteData(0x0a); 
    SPI_WriteComm(0x54);SPI_WriteData(0x11); 
    SPI_WriteComm(0x55);SPI_WriteData(0xec); 
    SPI_WriteComm(0x56);SPI_WriteData(0xed); 
    SPI_WriteComm(0x57);SPI_WriteData(0x11); 
    SPI_WriteComm(0x58);SPI_WriteData(0xef); 
    SPI_WriteComm(0x59);SPI_WriteData(0xf0); 
    SPI_WriteComm(0xB1);SPI_WriteData(0x01); 
    SPI_WriteComm(0xB4);SPI_WriteData(0x15); 
    SPI_WriteComm(0xB5);SPI_WriteData(0x16); 
    SPI_WriteComm(0xB6);SPI_WriteData(0x09); 
    SPI_WriteComm(0xB7);SPI_WriteData(0x0f); 
    SPI_WriteComm(0xB8);SPI_WriteData(0x0d); 
    SPI_WriteComm(0xB9);SPI_WriteData(0x0b); 
    SPI_WriteComm(0xBA);SPI_WriteData(0x00); 
    SPI_WriteComm(0xC7);SPI_WriteData(0x02); 
    SPI_WriteComm(0xCA);SPI_WriteData(0x17); 
    SPI_WriteComm(0xCB);SPI_WriteData(0x18); 
    SPI_WriteComm(0xCC);SPI_WriteData(0x0a); 
    SPI_WriteComm(0xCD);SPI_WriteData(0x10); 
    SPI_WriteComm(0xCE);SPI_WriteData(0x0e); 
    SPI_WriteComm(0xCF);SPI_WriteData(0x0c); 
    SPI_WriteComm(0xD0);SPI_WriteData(0x00); 
    SPI_WriteComm(0x81);SPI_WriteData(0x00); 
    SPI_WriteComm(0x84);SPI_WriteData(0x15); 
    SPI_WriteComm(0x85);SPI_WriteData(0x16); 
    SPI_WriteComm(0x86);SPI_WriteData(0x10); 
    SPI_WriteComm(0x87);SPI_WriteData(0x0a); 
    SPI_WriteComm(0x88);SPI_WriteData(0x0c); 
    SPI_WriteComm(0x89);SPI_WriteData(0x0e);
    SPI_WriteComm(0x8A);SPI_WriteData(0x02); 
    SPI_WriteComm(0x97);SPI_WriteData(0x00); 
    SPI_WriteComm(0x9A);SPI_WriteData(0x17); 
    SPI_WriteComm(0x9B);SPI_WriteData(0x18);
    SPI_WriteComm(0x9C);SPI_WriteData(0x0f);
    SPI_WriteComm(0x9D);SPI_WriteData(0x09); 
    SPI_WriteComm(0x9E);SPI_WriteData(0x0b); 
    SPI_WriteComm(0x9F);SPI_WriteData(0x0d); 
    SPI_WriteComm(0xA0);SPI_WriteData(0x01); 
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);
    SPI_WriteComm(0xFF);SPI_WriteData(0x02);  
    // SPI_WriteComm(0x01);SPI_WriteData(0x01);
    SPI_WriteComm(0x02);SPI_WriteData(0xDA);
    SPI_WriteComm(0x03);SPI_WriteData(0xBA);
    SPI_WriteComm(0x04);SPI_WriteData(0xA8);
    SPI_WriteComm(0x05);SPI_WriteData(0x9A);
    SPI_WriteComm(0x06);SPI_WriteData(0x70);
    SPI_WriteComm(0x07);SPI_WriteData(0xFF);
    SPI_WriteComm(0x08);SPI_WriteData(0x91);
    SPI_WriteComm(0x09);SPI_WriteData(0x90);
    SPI_WriteComm(0x0A);SPI_WriteData(0xFF);//DispRegValue(0x0a, 1); /* 写入后立即读取 */
    SPI_WriteComm(0x0B);SPI_WriteData(0x8F);
    SPI_WriteComm(0x0C);SPI_WriteData(0x60);
    SPI_WriteComm(0x0D);SPI_WriteData(0x58);
    SPI_WriteComm(0x0E);SPI_WriteData(0x48);
    SPI_WriteComm(0x0F);SPI_WriteData(0x38);
    SPI_WriteComm(0x10);SPI_WriteData(0x2B);
    SPI_WriteComm(0xFF);SPI_WriteData(0x30);
    SPI_WriteComm(0xFF);SPI_WriteData(0x52);
    SPI_WriteComm(0xFF);SPI_WriteData(0x00);
    SPI_WriteComm(0x36);SPI_WriteData(0x0a);


    SPI_WriteComm(0x11);SPI_WriteData(0x00);	 //sleep out
    // mdelay( 200 );

    SPI_WriteComm(0x29);SPI_WriteData(0x00);	  //display on
    // mdelay(10);
}
module_init(lcd_spi_init);
module_exit(lcd_spi_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("glink devices user space export");



/*

echo 116 > /sys/class/gpio/export
echo 117 > /sys/class/gpio/export
echo 122 > /sys/class/gpio/export
echo 123 > /sys/class/gpio/export


echo out > /sys/class/gpio/gpio116/direction
echo out > /sys/class/gpio/gpio117/direction
echo out > /sys/class/gpio/gpio122/direction
echo out > /sys/class/gpio/gpio123/direction


echo 0 > /sys/class/gpio/gpio116/value
echo 0 > /sys/class/gpio/gpio117/value
echo 0 > /sys/class/gpio/gpio122/value
echo 0 > /sys/class/gpio/gpio123/value


echo 1 > /sys/class/gpio/gpio116/value
echo 1 > /sys/class/gpio/gpio117/value
echo 1 > /sys/class/gpio/gpio122/value
echo 1 > /sys/class/gpio/gpio123/value
*/
